#include "SDL_opengl.h"
#include <cmath>

#ifndef OPENGL_GRAPHICS_H
#define OPENGL_GRAPHICS_H

GLfloat WHITE_GL[] = {GLfloat(1.0f), GLfloat(1.0f), GLfloat(1.0f), GLfloat(1.0f)};
GLfloat RED_GL[] = {1.0f, 0.0f, 0.0f, 1.0f};
GLfloat BLUE_GL[] = {0.0f, 0.0f, 1.0f, 1.0f};
GLfloat GREEN_GL[] = {0.0f, 1.0f, 0.0f, 1.0f};
GLfloat ORANGE_GL[] = {1.0f, 0.65f, 0.0f, 1.0f};

bool initGL(int screenWidth, int screenHeight)
{	
    // Set clear color to black
    glClearColor(0, 0, 0, 0);

	// enable alpha blending for drawing fonts
	glBlendFunc(GL_ONE, GL_ONE);
	glEnable(GL_BLEND);
    
    // Set projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	glOrtho(0, screenWidth, screenHeight, 0, -1, 1); // 2d perspective
    
    // Initialize modelview matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    // check for errors
    if(glGetError() != GL_NO_ERROR)
        return false;
    
    return true;
}

void ClearScreenGL()
{
	glClear(GL_COLOR_BUFFER_BIT);
}

void putpixelGL(GLfloat x, GLfloat y, const GLfloat *color)
{
	glBegin(GL_POINTS);
	{
		glColor4fv(color);
		glVertex2f(x, y);
	}
	glEnd();
}

void putpixelsGL(GLfloat* xyList, GLfloat** colors, int size)
{
	glBegin(GL_POINTS);
	{
		for (int i = 0; i < size; i++)
		{
			glColor4fv(colors[i]);
			glVertex2f(xyList[i], xyList[i + size]);
		}
	}
	glEnd();
}

void putlineGL(int x1, int x2, int y1, int y2, const GLfloat *color)
{
	
}

void putcircleGL(int x, int y, const GLfloat *color)
{

}

void blitGL(int x, int y, SDL_Surface *sdlSurface)
{
	
}

int round_dtoint(double x)
{
	return (int)(x + 0.5);
}

int nextpoweroftwo(int x)
{
	return round_dtoint(pow(2,ceil(log((float)x) / log((float)2))));
}

void blitTextGL(const char *text, 
                      TTF_Font *font,
                      SDL_Color color,
                      int x, int y)
{
	SDL_Surface *initial;
	SDL_Surface *intermediary;
	int w,h;
	GLuint texture;
	
	/* Use SDL_TTF to render our text */
	initial = TTF_RenderText_Blended(font, text, color);
	
	/* Convert the rendered text to a known format */
	w = nextpoweroftwo(initial->w);
	h = nextpoweroftwo(initial->h);
	
	intermediary = SDL_CreateRGBSurface(0, w, h, 32, 
			0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);

	SDL_BlitSurface(initial, 0, intermediary, 0);
	
	/* Tell GL about our new texture */
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, 
			GL_UNSIGNED_BYTE, intermediary->pixels );
	
	/* GL_NEAREST looks horrible, if scaled... */
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	

	/* prepare to render our texture */
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture);
	glColor3f(1.0f, 1.0f, 1.0f);
	
	/* Draw a quad at location */
	glBegin(GL_QUADS);
		/* Recall that the origin is in the lower-left corner
		   That is why the TexCoords specify different corners
		   than the Vertex coors seem to. */
		glTexCoord2f(0.0f, 0.0f); 
		glVertex2f(x, y);
		glTexCoord2f(1.0f, 0.0f); 
		glVertex2f(x + w, y);
		glTexCoord2f(1.0f, 1.0f); 
		glVertex2f(x + w, y + h);
		glTexCoord2f(0.0f, 1.0f); 
		glVertex2f(x, y + h);
	glEnd();
	
	/* Bad things happen if we delete the texture before it finishes */
	glFinish();
	
	/* Clean up */
	SDL_FreeSurface(initial);
	SDL_FreeSurface(intermediary);
	glDeleteTextures(1, &texture);
}

/* SDL methods required for rendering text */

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
const Uint32 RMASK = 0xff000000;
const Uint32 GMASK = 0x00ff0000;
const Uint32 BMASK = 0x0000ff00;
const Uint32 AMASK = 0x000000ff;
#else
const Uint32 RMASK = 0x000000ff;
const Uint32 GMASK = 0x0000ff00;
const Uint32 BMASK = 0x00ff0000;
const Uint32 AMASK = 0xff000000;
#endif

void sdlBlit(int x, int y, SDL_Surface* source, SDL_Surface* dest, SDL_Rect* clip)
{
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;
	SDL_BlitSurface(source, clip, dest, &offset);
}

SDL_Surface* renderBlockText(std::string text, TTF_Font* textFont, SDL_Color textColor, int x, int y, int depth)
{
	SDL_Surface* sum;
	SDL_Surface* temp;
	int tempWidth;
	int largestWidth = 0;
	int index = 0;
	int oldIndex = 0;
	int i, numLines = 0;
	std::list<std::string> strList;
	std::list<std::string>::iterator I;
	
	do {
		index = text.find('\n', oldIndex);
		strList.push_back(text.substr(oldIndex, index - oldIndex));
		TTF_SizeText(textFont, strList.back().c_str(), &tempWidth, NULL);
		if (tempWidth > largestWidth)
			largestWidth = tempWidth;
		oldIndex = index + 1;
		numLines++;
	} while (index != std::string::npos);
	
	I = strList.begin();
	sum = SDL_CreateRGBSurface(SDL_SWSURFACE, largestWidth, numLines * TTF_FontHeight(textFont), depth, RMASK, GMASK, BMASK, AMASK);

	for (i = 0; i < numLines; i++)
	{
		temp = TTF_RenderText_Blended(textFont, (*I++).c_str(), textColor);
		sdlBlit(x, y + TTF_FontHeight(textFont) * i, temp, sum, NULL);
		SDL_FreeSurface(temp);
	}
	
	return sum;
}

void blitBlockTextGL(std::string text, TTF_Font* textFont, SDL_Color textColor, int x, int y, int depth)
{
	int tempWidth;
	int largestWidth = 0;
	int index = 0;
	int oldIndex = 0;
	int i, numLines = 0;
	std::list<std::string> strList;
	std::list<std::string>::iterator I;
	
	do {
		index = text.find('\n', oldIndex);
		strList.push_back(text.substr(oldIndex, index - oldIndex));
		TTF_SizeText(textFont, strList.back().c_str(), &tempWidth, NULL);
		if (tempWidth > largestWidth)
			largestWidth = tempWidth;
		oldIndex = index + 1;
		numLines++;
	} while (index != std::string::npos);
	
	I = strList.begin();

	for (i = 0; i < numLines; i++)
		blitTextGL((*I++).c_str(), textFont, textColor, x, y + TTF_FontHeight(textFont) * i);
}

#endif